package com.atguigu.gulimall.product.controller;

import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.product.service.TestService;
import org.aspectj.weaver.ast.Test;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Controller
@RequestMapping("/test")
public class TestController {


    @Autowired
    RedissonClient redissonClient;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    TestService testService;

    @GetMapping("/cache")
    @ResponseBody
    public R cache(){
        List list = testService.list();
        return R.ok().put("list",list);
    }

    @GetMapping("/redisson/lock")
    @ResponseBody
    public R lock(){
        //1、获取锁，只要锁的名字一样就是同一把锁
        RLock lock = redissonClient.getLock("my-lock");

        //2、加锁.
        //自动解锁：阻塞式等待。默认有效期30秒。
        // 锁会自动续期，如果业务超长，运行期间会自动给锁续30秒。不用担心过期被删掉
        // 只要加锁的业务运行完成，就不会再续期，即使不手动解锁或宕机无法解锁，也会在30秒后自动删除。
        // 看门狗原理：占锁成功就会启动一个定时任务【默认时间过了三分一后重新给锁设置过期时间，新的过期时间就是看门狗的默认时间】
        lock.lock();

        //手动解锁：最佳实践，省去了整个续期操作，只要过期时间设置长点即可
        // lock.lock(10, TimeUnit.SECONDS);//设定10秒自动解锁且不会自动续期，自动解锁时间必须大于业务执行时间
        try {
            System.out.println("加锁成功，执行业务。。。" + Thread.currentThread().getId());
            Thread.sleep(3000);
        } catch (Exception e) {

        }finally {
            //3、解锁：
            System.out.println("释放锁。。。" + Thread.currentThread().getId());
            lock.unlock();
        }
        return R.ok();
    }


    @GetMapping("/redisson/write")
    @ResponseBody
    public R write(){
        //获取一个读写锁
        RReadWriteLock lock = redissonClient.getReadWriteLock("rw-lock");
        //改数据加写锁，读数据加读锁
        RLock rLock = lock.writeLock();
        String s = "";
        try {
            //加锁
            rLock.lock();
            System.out.println("写锁加锁成功，执行业务。。。" + Thread.currentThread().getId());
            //执行业务代码
            s = UUID.randomUUID().toString();
            Thread.sleep(5000);
            redisTemplate.opsForValue().set("writeValue",s);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //解锁
            rLock.unlock();
        }
        return R.ok(s);
    }
    @GetMapping("/redisson/read")
    @ResponseBody
    public R read(){
        //获取一个读写锁
        RReadWriteLock lock = redissonClient.getReadWriteLock("rw-lock");
        //改数据加写锁，读数据加读锁
        RLock rLock = lock.readLock();
        String s = "";
        try {
            //加锁
            rLock.lock();
            System.out.println("读锁加锁成功，执行业务。。。" + Thread.currentThread().getId());
            s = redisTemplate.opsForValue().get("writeValue")+"";
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //解锁
            rLock.unlock();
        }
        return R.ok(s);
    }
    @GetMapping("/redisson/park")
    @ResponseBody
    public R park(){
        //信号量
        RSemaphore park = redissonClient.getSemaphore("park");
        //获取一个信号 -1
        boolean b = park.tryAcquire();
        if (b) {
            //执行业务
            return R.ok("走了一辆车");
        } else {
            return R.error("车场空了");
        }

    }

    @GetMapping("/redisson/go")
    @ResponseBody
    public R go(){
        RSemaphore park = redissonClient.getSemaphore("park");
        //释放一个信号 +1
        park.release();
        return R.ok("停了一辆车");
    }


    @GetMapping("/redisson/lockDoor")
    @ResponseBody
    public R lockDoor() throws InterruptedException {
        //闭锁
        RCountDownLatch door = redissonClient.getCountDownLatch("door");
        //设置需要等待闭锁的数量
        door.trySetCount(5);
        //等待闭锁完成
        door.await();
        return R.ok("完成全部闭锁");
    }

    @GetMapping("/redisson/overDoor")
    @ResponseBody
    public R overDoor() {
        //闭锁
        RCountDownLatch door = redissonClient.getCountDownLatch("door");
        //完成闭锁,计数减一
        door.countDown();
        return R.ok("完成一个闭锁");
    }


}
